package cn.xzqwjw.taskmanager.security.filter;

import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author rush
 */
public class OptionsRequestFilter extends OncePerRequestFilter {

  /*
   * OPTIONS请求方法的主要用途有三个：
   * 1、获取服务器支持的HTTP请求方法；也是黑客经常使用的方法。
   * 2、用来检查服务器的性能。例如：AJAX进行跨域请求时的预检，
   * 需要向另外一个域名的资源发送一个HTTP OPTIONS请求头，用以判断实际发送的请求是否安全。
   * 3、检测到请求方法是options，不会有与服务器的数据交互。
   */

  /**
   * 定义一个过滤器，用来过滤 Option 请求
   * 如果是Option请求就自定义响应头
   */
  @Override
  protected void doFilterInternal(HttpServletRequest request,
                                  HttpServletResponse response,
                                  FilterChain filterChain)
      throws ServletException, IOException {
    String origin = request.getHeader("Origin");
    if (StringUtils.hasText(origin)) {
      response.addHeader("Access-Control-Allow-Origin", origin);
    }
    // 指定哪些客户端的域名允许访问这个资源
    // response.setHeader("Access-Control-Allow-Origin", "*");
    // 服务器允许浏览器带 cookie 上来，不设这个服务器端就无法获得请求里的cookie
    // response.setHeader("Access-Control-Allow-Credentials", "true");
    // 服务器支持的方法 比如POST GET之类的
    response.setHeader("Access-Control-Allow-Methods", "POST,DELETE,PUT,PATCH,GET,OPTIONS");
    // 告诉浏览器多久不需要再发出预检请求
    // 告诉浏览器缓存OPTIONS预检请求1小时，避免非简单请求每次发送预检请求，提升性能
    response.setHeader("Access-Control-Max-Age", "3600");
    // 需要在正式请求中加入的header值，否则正式请求会被拒绝，也是预检请求的响应中带回去的
    response.setHeader("Access-Control-Allow-Headers", request.getHeader("Access-Control-Request-Headers"));
    response.setHeader("Access-Control-Allow-Headers", "content-type, authorization");
    // 设置支持所有的自定义请求头
    String headers = request.getHeader("Access-Control-Request-Headers");
    if (StringUtils.hasText(headers)) {
      response.addHeader("Access-Control-Allow-Headers", headers);
    }
    if ("OPTIONS".equals(request.getMethod())) {
      response.setStatus(HttpServletResponse.SC_OK);
    } else {
      filterChain.doFilter(request, response);
    }
  }

}
